home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / 1.098 / vm / ds5000.md / vm3maxAsm.s < prev    next >
Text File  |  1991-03-05  |  23KB  |  984 lines

  1. /* vmPmaxAsm.s -
  2.  *
  3.  *    Subroutines to access PMAX virtual memory mapping hardware.
  4.  *
  5.  * Copyright (C) 1989 Digital Equipment Corporation.
  6.  * Permission to use, copy, modify, and distribute this software and
  7.  * its documentation for any purpose and without fee is hereby granted,
  8.  * provided that the above copyright notice appears in all copies.  
  9.  * Digital Equipment Corporation makes no representations about the
  10.  * suitability of this software for any purpose.  It is provided "as is"
  11.  * without express or implied warranty.
  12.  *
  13.  * $Header: /sprite/src/kernel/vm/ds5000.md/RCS/vm3maxAsm.s,v 1.2 91/03/05 15:12:05 jhh Exp $ SPRITE (DECWRL)
  14.  */
  15.  
  16. #include "vm3maxConst.h"
  17. #include "machAsmDefs.h"
  18. #include <regdef.h>
  19.  
  20.  
  21. /*
  22.  *--------------------------------------------------------------------------
  23.  *
  24.  * VmMachWriteTLB --
  25.  *
  26.  *    Write the given entry into the TLB.
  27.  *
  28.  *    VmMachWriteTLB(lowEntry, highEntry)
  29.  *        unsigned    lowEntry;
  30.  *        unsigned    highEntry;
  31.  *
  32.  *    Results:
  33.  *        Returns the old index corresponding to the high register.
  34.  *
  35.  *    Side effects:
  36.  *        TLB entry set.
  37.  *
  38.  *--------------------------------------------------------------------------
  39.  */
  40. LEAF(VmMachWriteTLB)
  41. .set noreorder
  42.     mfc0    t0, VMMACH_TLB_HI    # Save the high register because this
  43.     nop                    #   contains the current PID.
  44.     mtc0    a1, VMMACH_TLB_HI    # Store into the high register.
  45.     nop
  46.     tlbp                # Probe for value.
  47.     mfc0    v0, VMMACH_TLB_INDEX    # See what index we got.  This value
  48.                     #   is returned as the result of this
  49.                     #   procedure.
  50.     mtc0    a0, VMMACH_TLB_LOW    # Set the low register.
  51.     nop
  52.     bltz    v0, 1f            # index < 0 means not found
  53.     nop
  54.     tlbwi                # Reuse the entry that we found
  55.     mtc0    t0, VMMACH_TLB_HI    # Restore the PID.
  56.     j        ra            
  57.     nop
  58. 1:  tlbwr                # Write a random entry.
  59.     mtc0    t0, VMMACH_TLB_HI    # Restore the PID
  60.     j        ra
  61.     nop
  62. .set reorder
  63. END(VmMachWriteTLB)
  64.  
  65.  
  66. /*
  67.  *--------------------------------------------------------------------------
  68.  *
  69.  * VmMachWriteIndexedTLB --
  70.  *
  71.  *    Write the given entry into the TLB at the given index.
  72.  *
  73.  *    VmMachWriteTLB(index, lowEntry, highEntry)
  74.  *        unsigned    index;
  75.  *        unsigned    lowEntry;
  76.  *        unsigned    highEntry;
  77.  *
  78.  *    Results:
  79.  *        None.
  80.  *
  81.  *    Side effects:
  82.  *        TLB entry set.
  83.  *
  84.  *--------------------------------------------------------------------------
  85.  */
  86. LEAF(VmMachWriteIndexedTLB)
  87. .set noreorder
  88.     mfc0    t0, VMMACH_TLB_HI    # Save the high register because this
  89.                     #   contains the current PID.
  90.  
  91.     sll        a0, a0, VMMACH_TLB_INDEX_SHIFT
  92.     mtc0    a0, VMMACH_TLB_INDEX    # Set the index.
  93.     mtc0    a1, VMMACH_TLB_LOW    # Set up entry low.
  94.     mtc0    a2, VMMACH_TLB_HI    # Set up entry high.
  95.     nop
  96.     tlbwi                # Write the TLB
  97.  
  98.     mtc0    t0, VMMACH_TLB_HI    # Restore the PID.
  99.  
  100.     j        ra
  101.     nop
  102. .set reorder
  103. END(VmMachWriteIndexedTLB)
  104.  
  105. /* 
  106.  *--------------------------------------------------------------------------
  107.  *
  108.  * VmMachFlushPIDFromTLB --
  109.  *
  110.  *    Flush all pages for the given PID from the TLB.
  111.  *
  112.  *    VmMachFlushPIDFromTLB(pid)
  113.  *        int        pid;
  114.  *
  115.  *    Results:
  116.  *        None.
  117.  *
  118.  *    Side effects:
  119.  *        All entries corresponding to this PID are flushed.
  120.  *
  121.  *--------------------------------------------------------------------------
  122.  */
  123. LEAF(VmMachFlushPIDFromTLB)
  124. .set noreorder
  125.     subu    sp, sp, STAND_FRAME_SIZE
  126.     sw        ra, STAND_RA_OFFSET(sp)
  127.     sw        a0, STAND_FRAME_SIZE(sp)
  128.     .mask    0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
  129.  
  130.     mfc0    t0, VMMACH_TLB_HI        # Save the PID
  131.     sll        a0, a0, VMMACH_TLB_PID_SHIFT    # Align the pid to flush.
  132.  
  133. /*
  134.  * Align the starting value (t1), the increment (t2) and the upper bound (t3).
  135.  */
  136.     li        t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
  137.     li        t2, 1 << VMMACH_TLB_INDEX_SHIFT
  138.     li        t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
  139.  
  140. 1:  mtc0    t1, VMMACH_TLB_INDEX        # Set the index register
  141.     addu    t1, t1, t2            # Increment index.
  142.     tlbr                    # Read from the TLB    
  143.     mfc0    t4, VMMACH_TLB_HI        # Fetch the hi register.
  144.     nop
  145.     and        t4, t4, a0            # See if the pids match.
  146.     bne        t4, a0, 2f
  147.     li        t4, VMMACH_PHYS_CACHED_START
  148.     mtc0    t4, VMMACH_TLB_HI        # Mark entry high as invalid
  149.     mtc0    zero, VMMACH_TLB_LOW        # Zero out entry low.
  150.     nop
  151.     tlbwi                    # Write the entry.
  152. 2:
  153.     bne        t1, t3, 1b
  154.     nop
  155.  
  156.     mtc0    t0, VMMACH_TLB_HI
  157.     addu    sp, sp, STAND_FRAME_SIZE
  158.  
  159.     j        ra
  160.     nop
  161. .set reorder
  162. END(VmMachFlushPIDFromTLB)
  163.  
  164.  
  165. /* 
  166.  *--------------------------------------------------------------------------
  167.  *
  168.  * VmMachFlushTLB --
  169.  *
  170.  *    Flush the TLB.
  171.  *
  172.  *    VmMachFlushTLB()
  173.  *
  174.  *    Results:
  175.  *        None.
  176.  *
  177.  *    Side effects:
  178.  *       The TLB is flushed.
  179.  *
  180.  *--------------------------------------------------------------------------
  181.  */
  182. LEAF(VmMachFlushTLB)
  183. .set noreorder
  184.     subu    sp, sp, STAND_FRAME_SIZE
  185.     sw        ra, STAND_RA_OFFSET(sp)
  186.     .mask    0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
  187.  
  188.     mfc0    t0, VMMACH_TLB_HI        # Save the PID
  189.     li        t1, VMMACH_PHYS_CACHED_START
  190.     mtc0    t1, VMMACH_TLB_HI        # Invalidate hi entry.
  191.     mtc0    zero, VMMACH_TLB_LOW        # Zero out entry low.
  192.  
  193. /*
  194.  * Align the starting value (t1), the increment (t2) and the upper bound (t3).
  195.  */
  196.     li        t1, VMMACH_FIRST_RAND_ENTRY << VMMACH_TLB_INDEX_SHIFT
  197.     li        t2, 1 << VMMACH_TLB_INDEX_SHIFT
  198.     li        t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
  199.  
  200. 1:  mtc0    t1, VMMACH_TLB_INDEX        # Set the index register.
  201.     addu    t1, t1, t2            # Increment index.
  202.     tlbwi                    # Write the TLB entry.
  203.     bne        t1, t3, 1b
  204.     nop
  205.  
  206.     mtc0    t0, VMMACH_TLB_HI        # Restore the PID
  207.     addu    sp, sp, STAND_FRAME_SIZE
  208.  
  209.     j        ra
  210.     nop
  211. .set reorder
  212. END(VmMachFlushTLB)
  213.  
  214.  
  215. /* 
  216.  *--------------------------------------------------------------------------
  217.  *
  218.  * VmMachFlushPageFromTLB --
  219.  *
  220.  *    Flush the given page from the TLB for the given process.
  221.  *
  222.  *    VmMachFlushPageFromTLB(pid, page)
  223.  *
  224.  *    Results:
  225.  *        None.
  226.  *
  227.  *    Side effects:
  228.  *       The process's page is flushed from the TLB.
  229.  *
  230.  *--------------------------------------------------------------------------
  231.  */
  232. LEAF(VmMachFlushPageFromTLB)
  233. .set noreorder
  234.     mfc0    t0, VMMACH_TLB_HI            # Save PID
  235.  
  236.     sll        a0, a0, VMMACH_TLB_PID_SHIFT        # Align pid
  237.     sll        a1, a1, VMMACH_TLB_VIRT_PAGE_SHIFT    # Align virt page
  238.     or        t1, a0, a1                # Set up entry.
  239.     mtc0    t1, VMMACH_TLB_HI            # Put into high reg.
  240.     nop
  241.     tlbp                        # Probe for the entry.
  242.     mfc0    v0, VMMACH_TLB_INDEX            # See what we got
  243.     li        t1, VMMACH_PHYS_CACHED_START        # Load invalid entry.
  244.     bltz    v0, 1f                    # index < 0 => !found
  245.     nop
  246.     mtc0    t1, VMMACH_TLB_HI            # Prepare index hi.
  247.     mtc0    zero, VMMACH_TLB_LOW            # Prepare index lo.
  248.     nop
  249.     tlbwi
  250.  
  251. 1:
  252.     mtc0    t0, VMMACH_TLB_HI            # Restore the PID
  253.     j        ra
  254.     nop
  255.  
  256. .set reorder
  257. END(VmMachFlushPageFromTLB)
  258.  
  259.  
  260. /* 
  261.  *--------------------------------------------------------------------------
  262.  *
  263.  * VmMachClearTLBModBit --
  264.  *
  265.  *    Clear the modified bit for the given <pid, page> pair.
  266.  *
  267.  *    VmMachClearTLBModBit(pid, page)
  268.  *
  269.  *    Results:
  270.  *        None.
  271.  *
  272.  *    Side effects:
  273.  *       The process's page is flushed from the TLB.
  274.  *
  275.  *--------------------------------------------------------------------------
  276.  */
  277. LEAF(VmMachClearTLBModBit)
  278. .set noreorder
  279.     mfc0    t0, VMMACH_TLB_HI            # Save PID
  280.  
  281.     sll        a0, a0, VMMACH_TLB_PID_SHIFT        # Align pid
  282.     sll        a1, a1, VMMACH_TLB_VIRT_PAGE_SHIFT    # Align virt page
  283.     or        t1, a0, a1                # Set up entry.
  284.     mtc0    t1, VMMACH_TLB_HI            # Put into high reg.
  285.     nop
  286.     tlbp                        # Probe for the entry.
  287.     mfc0    v0, VMMACH_TLB_INDEX            # See what we got
  288.     nop
  289.     bltz    v0, 1f                    # index < 0 => !found
  290.     nop
  291.     tlbr
  292.     mfc0    t1, VMMACH_TLB_LOW            # Read out low.
  293.     nop
  294.     and        t1, t1, ~VMMACH_TLB_MOD_BIT
  295.     mtc0    t1, VMMACH_TLB_LOW            # Write index low.
  296.     nop
  297.     tlbwi                        # Write the TLB entry.
  298.  
  299. 1:
  300.     mtc0    t0, VMMACH_TLB_HI            # Restore the PID
  301.     j        ra
  302.     nop
  303.  
  304. .set reorder
  305. END(VmMachClearTLBModBit)
  306.  
  307. #ifdef notdef
  308.  
  309. /* 
  310.  *--------------------------------------------------------------------------
  311.  *
  312.  * VmMachFlushGlobalPageFromTLB --
  313.  *
  314.  *    Flush the given page from the TLB for the given process.
  315.  *
  316.  *    VmMachFlushPageFromTLB(pid, page)
  317.  *
  318.  *    Results:
  319.  *        None.
  320.  *
  321.  *    Side effects:
  322.  *       The process's page is flushed from the TLB.
  323.  *
  324.  *--------------------------------------------------------------------------
  325.  */
  326. LEAF(VmMachFlushGlobalPageFromTLB)
  327. .set noreorder
  328.     subu    sp, sp, STAND_FRAME_SIZE
  329.     sw        ra, STAND_RA_OFFSET(sp)
  330.     .mask    0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
  331.  
  332.     mfc0    t0, VMMACH_TLB_HI            # Save PID
  333.  
  334.     sll        t1, a0, VMMACH_TLB_VIRT_PAGE_SHIFT    # Align virt page
  335.  
  336.     add        t2, zero, zero
  337.     li        t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
  338.     li        v0, 0x80000000
  339.  
  340. 6:  mtc0    t2, VMMACH_TLB_INDEX            # Set index
  341.     nop
  342.     tlbr                        # Read an entry.
  343.     mfc0    t4, VMMACH_TLB_HI
  344.     nop
  345.     and        t4, t4, VMMACH_TLB_VIRT_PAGE_NUM
  346.     bne        t4, t1, 2f                # test for pid/vpn match
  347.     nop
  348.  
  349.     add        v0, t2, zero
  350.     li        t4, VMMACH_PHYS_CACHED_START
  351.     mtc0    t4, VMMACH_TLB_HI            # Prepare index hi
  352.     mtc0    zero, VMMACH_TLB_LOW            # Prepare index lo
  353.     nop
  354.     tlbwi                        # Invalidate entry
  355. 2:
  356.     add        t2, t2, 1 << VMMACH_TLB_INDEX_SHIFT
  357.     bne        t2, t3, 6b
  358.     nop
  359.  
  360. 4:  mtc0    t0, VMMACH_TLB_HI    
  361.     addu    sp, sp, STAND_FRAME_SIZE
  362.     j        ra
  363.     nop
  364.  
  365. .set reorder
  366. END(VmMachFlushGlobalPageFromTLB)
  367. #endif
  368.  
  369. /* 
  370.  *--------------------------------------------------------------------------
  371.  *
  372.  * VmMachDumpTLB --
  373.  *
  374.  *    Flush the TLB.
  375.  *
  376.  *    VmMachFlushTLB(tlbPtr)
  377.  *        unsigned *tlbPtr;
  378.  *
  379.  *    Results:
  380.  *        None.
  381.  *
  382.  *    Side effects:
  383.  *       The contents of the TLB are written to *tlbPtr.
  384.  *
  385.  *--------------------------------------------------------------------------
  386.  */
  387. LEAF(Vm_MachDumpTLB)
  388. .set noreorder
  389.     subu    sp, sp, STAND_FRAME_SIZE
  390.     sw        ra, STAND_RA_OFFSET(sp)
  391.     .mask    0x80000000, (STAND_RA_OFFSET - STAND_FRAME_SIZE)
  392.  
  393.     mfc0    t0, VMMACH_TLB_HI        # Save the PID
  394.  
  395. /*
  396.  * Align the starting value (t1), the increment (t2) and the upper bound (t3).
  397.  */
  398.     li        t1, 0
  399.     li        t2, 1 << VMMACH_TLB_INDEX_SHIFT
  400.     li        t3, VMMACH_NUM_TLB_ENTRIES << VMMACH_TLB_INDEX_SHIFT
  401.  
  402. 1:  mtc0    t1, VMMACH_TLB_INDEX        # Set the index register.
  403.     addu    t1, t1, t2            # Increment index.
  404.     tlbr                    # Read the TLB entry.
  405.     mfc0    t4, VMMACH_TLB_LOW
  406.     mfc0    t5, VMMACH_TLB_HI
  407.     sw        t4, 0(a0)
  408.     sw        t5, 4(a0)
  409.     add        a0, a0, 8
  410.     bne        t1, t3, 1b
  411.     nop
  412.  
  413.     mtc0    t0, VMMACH_TLB_HI        # Restore the PID
  414.     addu    sp, sp, STAND_FRAME_SIZE
  415.  
  416.     j        ra
  417.     nop
  418. .set reorder
  419. END(Vm_MachDumpTLB)
  420.  
  421. /* 
  422.  *--------------------------------------------------------------------------
  423.  *
  424.  * VmMachSetPID --
  425.  *
  426.  *    Write the given pid into the TLB pid reg.
  427.  *
  428.  *    VmMachWritePID(pid)
  429.  *        int        pid;
  430.  *
  431.  *    Results:
  432.  *        None.
  433.  *
  434.  *    Side effects:
  435.  *        PID set in the entry hi register.
  436.  *
  437.  *--------------------------------------------------------------------------
  438.  */
  439.     .globl VmMachSetPID
  440. VmMachSetPID:
  441.     sll        a0, a0, 6        # Reg 4 <<= 6 to put PID in right spot
  442.     mtc0    a0, VMMACH_TLB_HI    # Write the hi reg value
  443.     j        ra
  444.  
  445.  
  446. /*
  447.  * ----------------------------------------------------------------------
  448.  *
  449.  * Vm_Copy{In,Out}
  450.  *
  451.  *    Copy numBytes from *sourcePtr in to *destPtr.
  452.  *    This routine is optimized to do transfers when sourcePtr and 
  453.  *    destPtr are both 4-byte aligned.
  454.  *
  455.  *    ReturnStatus
  456.  *    Vm_Copy{In,Out}(numBytes, sourcePtr, destPtr)
  457.  *        register int numBytes;      * The number of bytes to copy *
  458.  *        Address sourcePtr;          * Where to copy from. *
  459.  *        Address destPtr;            * Where to copy to. *
  460.  *
  461.  *    NOTE: The trap handler assumes that this routine does not push anything
  462.  *          onto the stack.  It uses this fact to allow it to return to the
  463.  *          caller of this routine upon an address fault.  If you must push
  464.  *          something onto the stack then you had better go and modify 
  465.  *          "CallTrapHandler" in asmDefs.h appropriately.
  466.  *
  467.  * Results:
  468.  *    Returns SUCCESS if the copy went OK (which is almost always).  If
  469.  *    a bus error (other than a page fault) occurred while reading or
  470.  *    writing user memory, then SYS_ARG_NO_ACCESS is returned (this return
  471.  *    occurs from the trap handler, rather than from this procedure).
  472.  *
  473.  * Side effects:
  474.  *    The area that destPtr points to is modified.
  475.  *
  476.  * ----------------------------------------------------------------------
  477.  */
  478.     .globl VmMachDoCopy
  479.     .globl Vm_CopyIn
  480. VmMachDoCopy:
  481. Vm_CopyIn:
  482. /*
  483.  * The number of bytes was passed in in r4, the source in r5, and the dest
  484.  * in r6.
  485.  *
  486.  * If the source or dest are not 4 byte aligned then everything must be
  487.  * done as byte copies.
  488.  */
  489.  
  490. gotArgs:
  491.     or        t0, a1, a2
  492.     andi    t0, t0, 3
  493.     blez    t0, 1f
  494.     j        3f
  495.  
  496. /*
  497.  * Do as many 64-byte copies as possible.
  498.  */
  499.  
  500. 1:
  501.     sub        t0, a0, 64
  502.     bltz    t0, 2f
  503.     lw        t0, 0(a1)
  504.     lw        t1, 4(a1)
  505.     sw        t0, 0(a2)
  506.     sw        t1, 4(a2)
  507.     lw        t0, 8(a1)
  508.     lw        t1, 12(a1)
  509.     sw        t0, 8(a2)
  510.     sw        t1, 12(a2)
  511.     lw        t0, 16(a1)
  512.     lw        t1, 20(a1)
  513.     sw        t0, 16(a2)
  514.     sw        t1, 20(a2)
  515.     lw        t0, 24(a1)
  516.     lw        t1, 28(a1)
  517.     sw        t0, 24(a2)
  518.     sw        t1, 28(a2)
  519.     lw        t0, 32(a1)
  520.     lw        t1, 36(a1)
  521.     sw        t0, 32(a2)
  522.     sw        t1, 36(a2)
  523.     lw        t0, 40(a1)
  524.     lw        t1, 44(a1)
  525.     sw        t0, 40(a2)
  526.     sw        t1, 44(a2)
  527.     lw        t0, 48(a1)
  528.     lw        t1, 52(a1)
  529.     sw        t0, 48(a2)
  530.     sw        t1, 52(a2)
  531.     lw        t0, 56(a1)
  532.     lw        t1, 60(a1)
  533.     sw        t0, 56(a2)
  534.     sw        t1, 60(a2)
  535.     sub        a0, a0, 64
  536.     add        a1, a1, 64
  537.     add        a2, a2, 64
  538.     j        1b
  539.  
  540. /*
  541.  * Do 4 byte copies.
  542.  */
  543. 2:
  544.     sub        t0, a0, 4
  545.     bltz    t0, 3f
  546.     lw        t0, 0(a1)
  547.     sw        t0, 0(a2)
  548.     sub        a0, a0, 4
  549.     add        a1, a1, 4
  550.     add        a2, a2, 4
  551.     j        2b
  552.  
  553. /*
  554.  * Do one byte copies until done.
  555.  */
  556.  
  557. 3:
  558.     beq        a0, zero, 4f
  559.     lb        t0, 0(a1)
  560.     sb        t0, 0(a2)
  561.     sub        a0, a0, 1
  562.     add        a1, a1, 1
  563.     add        a2, a2, 1
  564.     j        3b
  565.  
  566. /* 
  567.  * Return.
  568.  */
  569. 4: 
  570.     li        v0, 0
  571.     j        ra
  572.  
  573. /* 
  574.  * Vm_CopyOut is just like Vm_CopyIn except that it checks to make sure
  575.  * that the destination is in the user area (otherwise this would be a
  576.  * trap door to write to kernel space).
  577.  */
  578.  
  579.     .globl Vm_CopyOut
  580. .ent Vm_CopyOut
  581. Vm_CopyOut:
  582. /*
  583.  * If a2 is < 0 then it is has the sign bit set which means its in the
  584.  * kernel's VAS.
  585.  */
  586.     bltz    a2, 5f
  587.     j        gotArgs
  588.  
  589. /*
  590.  * User address out of range.  Check for a zero byte count before
  591.  * returning an error, though;  there appear to be kernel routines
  592.  * that call Vm_CopyOut with a zero count but bogus other arguments.
  593.  */
  594.  
  595. 5:
  596.     blez    a0, 6f
  597.     lui        v0, 2
  598.     j        ra
  599. 6:  li        v0, 0
  600.     j        ra
  601. .end
  602.  
  603.  
  604. /*
  605.  * ----------------------------------------------------------------------
  606.  *
  607.  * Vm_StringNCopy
  608.  *
  609.  *    Copy the NULL terminated string from *sourcePtr to *destPtr up
  610.  *    numBytes worth of bytes.
  611.  *
  612.  *    void
  613.  *    Vm_StringNCopy(numBytes, sourcePtr, destPtr, bytesCopiedPtr)
  614.  *        register int numBytes;      * The number of bytes to copy *
  615.  *        Address sourcePtr;          * Where to copy from. *
  616.  *        Address destPtr;            * Where to copy to. *
  617.  *        int    *bytesCopiedPtr;    * Number of bytes copied. *
  618.  *
  619.  *    NOTE: The trap handler assumes that this routine does not push anything
  620.  *          onto the stack.  It uses this fact to allow it to return to the
  621.  *          caller of this routine upon an address fault.  If you must push
  622.  *          something onto the stack then you had better go and modify 
  623.  *          "CallTrapHandler" in asmDefs.h appropriately.
  624.  *
  625.  * Results:
  626.  *    Normally returns SUCCESS.  If a non-recoverable bus error occurs,
  627.  *    then the trap handler fakes up a SYS_ARG_NO_ACCESS return from
  628.  *    this procedure.
  629.  *
  630.  * Side effects:
  631.  *    The area that destPtr points to is modified and *bytesCopiedPtr 
  632.  *    contains the number of bytes copied.
  633.  *
  634.  * ----------------------------------------------------------------------
  635.  */
  636.     .globl  Vm_StringNCopy
  637. Vm_StringNCopy:
  638.     add        t2, a0, 0        # Save the number of bytes
  639. 1:
  640.     lb        t0, 0(a1)
  641.     sb        t0, 0(a2)
  642.     beq        t0, zero, 2f
  643.     add        a1, a1, 1
  644.     add        a2, a2, 1
  645.     sub        a0, a0, 1
  646.     bne        a0, zero, 1b
  647. 2: 
  648.     sub        a0, t2, a0
  649.     sw        a0, 0(a3)
  650.     li        v0, 0
  651.     j        ra
  652.  
  653.  
  654. /*
  655.  * ----------------------------------------------------------------------
  656.  *
  657.  * Vm_TouchPages --
  658.  *
  659.  *    Touch the range of pages.
  660.  *
  661.  *    void
  662.  *    Vm_TouchPages(firstPage, numPages)
  663.  *        int    firstPage;    * First page to touch. *
  664.  *        int    numPages;    * Number of pages to touch. *
  665.  *
  666.  *    NOTE: The trap handler assumes that this routine does not push anything
  667.  *          onto the stack.  It uses this fact to allow it to return to the
  668.  *          caller of this routine upon an address fault.
  669.  *
  670.  * Results:
  671.  *    Returns SUCCESS if were able to touch the page (which is almost
  672.  *    always).  If a bus error (other than a page fault) occurred while 
  673.  *    reading user memory, then SYS_ARG_NO_ACCESS is returned (this return
  674.  *    occurs from the trap handler, rather than from this procedure).
  675.  *
  676.  * Side effects:
  677.  *    None.
  678.  *
  679.  * ----------------------------------------------------------------------
  680.  */
  681.     .globl Vm_TouchPages
  682. Vm_TouchPages:
  683.     sll        a0, a0, VMMACH_PAGE_SHIFT
  684. 1:
  685.     beq        a1, zero, 2f
  686.     lw        t0, 0(a0)
  687.     sub        a1, a1, 1
  688.     add        a0, a0, VMMACH_PAGE_SIZE
  689.     j        1b
  690. 2:
  691.     j        ra
  692.  
  693.     .globl VmMachCopyEnd
  694. VmMachCopyEnd:
  695.  
  696. /*----------------------------------------------------------------------------
  697.  *
  698.  * VmMach_UTLBMiss --
  699.  *
  700.  *    Handle a user TLB miss.
  701.  *
  702.  *
  703.  * Results:
  704.  *         None.
  705.  *
  706.  * Side effects:
  707.  *    None.
  708.  *
  709.  *----------------------------------------------------------------------------
  710.  */
  711.     .globl VmMach_UTLBMiss
  712.     .ent VmMach_UTLBMiss
  713. VmMach_UTLBMiss:
  714. .set noat
  715. .set noreorder
  716.     mfc0    k0, VMMACH_TLB_HI            # Get the high val.
  717.     lui        k1, 0x8000            
  718.     sw        AT, VMMACH_SAVED_AT_OFFSET(k1)
  719. #ifndef NO_COUNTERS
  720.     lw        AT, VMMACH_UTLB_COUNT_OFFSET(k1)
  721.     nop    
  722.     add        AT, AT, 1
  723.     sw        AT, VMMACH_UTLB_COUNT_OFFSET(k1)
  724. #endif
  725.  
  726. /*
  727.  * Make the hash key.
  728.  */
  729.     srl        k1, k0, VMMACH_PAGE_HASH_SHIFT
  730.     sll        AT, k0, VMMACH_PID_HASH_SHIFT
  731.     xor        k1, k1, AT
  732. .set at
  733.     and        k1, k1, VMMACH_HASH_MASK
  734. .set noat
  735. /*
  736.  * Load the hash table key.
  737.  */
  738.     la        AT, vmMachTLBHashTable
  739.     add        AT, k1, AT
  740.     lw        k1, VMMACH_HASH_KEY_OFFSET(AT)
  741.     nop
  742.  
  743. /*
  744.  * Check for match.
  745.  */
  746.     beq        k1, k0, 1f
  747.     lw        k1, VMMACH_LOW_REG_OFFSET(AT)
  748.     j        SlowUTLBFault
  749. /*
  750.  * We have a match.  Restore AT and write the TLB entry.
  751.  */
  752. 1:
  753.     lui        AT, 0x8000
  754.     mtc0    k1, VMMACH_TLB_LOW
  755.     mfc0    k0, MACH_COP_0_EXC_PC
  756.     tlbwr
  757. #ifndef NO_COUNTERS
  758.     lw        k1, VMMACH_UTLB_HIT_OFFSET(AT)
  759.     nop
  760.     add        k1, k1, 1
  761.     sw        k1, VMMACH_UTLB_HIT_OFFSET(AT)
  762. #endif
  763.     lw        AT, VMMACH_SAVED_AT_OFFSET(AT)
  764.     j        k0
  765.     rfe
  766.     .end VmMach_UTLBMiss
  767.  
  768.     .globl VmMach_EndUTLBMiss
  769. VmMach_EndUTLBMiss:
  770. .set reorder
  771.  
  772. /*
  773.  * We couldn't find a TLB entry.  Find out what mode we came from and call
  774.  * the appropriate handler.
  775.  */
  776. SlowUTLBFault:
  777.     lui        AT, 0x8000
  778.     lw        AT, VMMACH_SAVED_AT_OFFSET(AT)
  779. .set reorder
  780.     mfc0    k0, MACH_COP_0_STATUS_REG
  781.     nop
  782.     and        k0, k0, MACH_SR_KU_PREV
  783.     bne        k0, zero, 1f
  784.     j        Mach_KernGenException
  785. 1:  j        Mach_UserGenException
  786.  
  787. .set at
  788.  
  789. /*----------------------------------------------------------------------------
  790.  *
  791.  * VmMach_KernTLBException --
  792.  *
  793.  *    Handle a kernel TLB fault.
  794.  *
  795.  * Results:
  796.  *         None.
  797.  *
  798.  * Side effects:
  799.  *    None.
  800.  *
  801.  *----------------------------------------------------------------------------
  802.  */
  803. str:
  804.     .asciiz    "Error on stack\n"
  805.     .globl VmMach_KernTLBException
  806.     .ent VmMach_KernTLBException, 0
  807. VmMach_KernTLBException:
  808. .set noreorder
  809. .set noat
  810.     mfc0    k0, MACH_COP_0_BAD_VADDR    # Get the faulting address
  811.     add        k1, sp, zero
  812.     srl        k1, k1, VMMACH_PAGE_SHIFT
  813.     srl        k0, k0, VMMACH_PAGE_SHIFT
  814.     bne        k0, k1, 1f
  815.     nop
  816.     la        a0, str
  817.     jal        panic
  818.     nop
  819.  
  820. 1:
  821.     mfc0    k0, MACH_COP_0_BAD_VADDR    # Get the faulting address
  822.     li        k1, VMMACH_VIRT_CACHED_START    # Get the lower bound
  823.     sltu    k1, k0, k1            # Compare to the lower bound
  824.     bne        k1, zero, KernGenException    #    and take a normal exception
  825.     nop                        #    if we are lower
  826.     li        k1, MACH_KERN_END        # Get the upper bound
  827.     sltu    k1, k0, k1            # Compare to the upper bound
  828.     beq        k1, zero, KernGenException    #    and take a normal exception
  829.                         #    if we are higher.
  830.     srl        k0, VMMACH_PAGE_SHIFT        # Get the virtual page number.
  831.     li        k1, VMMACH_VIRT_CACHED_START_PAGE
  832.     subu    k0, k0, k1
  833.     lw        k1, vmMach_KernelTLBMap        # Get to map that contains
  834.                         #     the TLB entry.
  835.     sll        k0, k0, 2            # Each entry is four bytes
  836.     add        k0, k0, k1            # Get pointer to entry.
  837.     lw        k0, 0(k0)            # Get entry
  838.     nop
  839.     beq        k0, zero, KernGenException    # If entry is zero then take
  840.                         #    a normal exception.
  841.     mtc0    k0, VMMACH_TLB_LOW        # Set the low entry.
  842.     mfc0    k1, MACH_COP_0_EXC_PC        # Get the exception PC
  843.     tlbwr                    # Write the entry out.
  844.     j        k1
  845.     rfe
  846.  
  847. KernGenException:
  848.     j        Mach_KernGenException
  849.     nop
  850.  
  851. .end VmMach_KernTLBException
  852. .set at
  853. .set reorder
  854.  
  855. /*----------------------------------------------------------------------------
  856.  *
  857.  * VmMach_TLBModException --
  858.  *
  859.  *    Handle a modified exception.
  860.  *
  861.  * Results:
  862.  *         None.
  863.  *
  864.  * Side effects:
  865.  *    None.
  866.  *
  867.  *----------------------------------------------------------------------------
  868.  */
  869.     .globl VmMach_TLBModException
  870.     .ent VmMach_TLBModException, 0
  871. VmMach_TLBModException:
  872. .set noat
  873. .set noreorder
  874.     mfc0    k0, VMMACH_TLB_HI            # Get the high val.
  875.     lui        k1, 0x8000
  876.     sw        AT, VMMACH_SAVED_AT_OFFSET(k1)
  877. #ifndef NO_COUNTERS
  878.     lw        AT, VMMACH_MOD_COUNT_OFFSET(k1)
  879.     nop    
  880.     add        AT, AT, 1
  881.     sw        AT, VMMACH_MOD_COUNT_OFFSET(k1)
  882. #endif
  883.  
  884. /*
  885.  * Make the hash key.
  886.  */
  887.     srl        k1, k0, VMMACH_PAGE_HASH_SHIFT
  888.     sll        AT, k0, VMMACH_PID_HASH_SHIFT
  889.     xor        k1, k1, AT
  890. .set at
  891.     and        k1, k1, VMMACH_HASH_MASK
  892. .set noat
  893. /*
  894.  * Load the hash table key.
  895.  */
  896.     la        AT, vmMachTLBHashTable
  897.     add        AT, k1, AT
  898.     lw        k1, VMMACH_HASH_KEY_OFFSET(AT)
  899.     nop
  900.  
  901. /*
  902.  * Check for match.
  903.  */
  904.     beq        k1, k0, 1f
  905.     nop
  906.     j        SlowModFault
  907.     nop
  908. /*
  909.  * We have a match.  See if we can write this page.
  910.  */
  911. 1:  
  912. #ifndef NO_COUNTERS
  913.     lui        k0, 0x8000
  914.     lw        k1, VMMACH_MOD_HIT_OFFSET(k0)
  915.     nop
  916.     add        k1, k1, 1
  917.     sw        k1, VMMACH_MOD_HIT_OFFSET(k0)
  918. #endif
  919.  
  920.     lw        k1, VMMACH_LOW_REG_OFFSET(AT)
  921.     nop
  922.     and        k0, k1, VMMACH_TLB_ENTRY_WRITEABLE
  923.     beq        k0, zero, SlowModFault
  924.     nop
  925. /*
  926.  * Find the entry in the TLB.  It has to be there since we took a mod fault
  927.  * on it.  While were at it set the mod bit in the hash table entry.
  928.  */
  929.     tlbp
  930.     mfc0    k0, VMMACH_TLB_INDEX
  931.     or        k1, k1, VMMACH_TLB_MOD_BIT
  932.     sw        k1, VMMACH_LOW_REG_OFFSET(AT)
  933.     bltz    k0, 1f
  934.     nop
  935. /*
  936.  * Write the TLB.
  937.  */
  938.     mtc0    k1, VMMACH_TLB_LOW
  939.     nop
  940.     tlbwi
  941. /*
  942.  * Set the modified bit in the physical page array.
  943.  */
  944. .set at
  945.     lw        k0, vmMachPhysPageArr
  946.     srl        k1, k1, VMMACH_TLB_PHYS_PAGE_SHIFT
  947.     sll        k1, k1, 2
  948.     add        k0, k0, k1
  949.     lw        k1, 0(k0)
  950.     nop
  951.     or        k1, k1, 4
  952.     sw        k1, 0(k0)
  953. .set noat
  954. /* 
  955.  * Restore AT and return.
  956.  */
  957.     mfc0    k0, MACH_COP_0_EXC_PC
  958.     lui        AT, 0x8000
  959.     lw        AT, VMMACH_SAVED_AT_OFFSET(AT)
  960.     j        k0
  961.     rfe
  962. 1:
  963.     break    0
  964. .set reorder
  965.  
  966. /*
  967.  * We couldn't find a TLB entry.  Find out what mode we came from and call
  968.  * the appropriate handler.
  969.  */
  970. SlowModFault:
  971.     lui        AT, 0x8000
  972.     lw        AT, VMMACH_SAVED_AT_OFFSET(AT)
  973. .set reorder
  974.     mfc0    k0, MACH_COP_0_STATUS_REG
  975.     nop
  976.     and        k0, k0, MACH_SR_KU_PREV
  977.     bne        k0, zero, 1f
  978.     j        Mach_KernGenException
  979. 1:  j        Mach_UserGenException
  980.  
  981. .end VmMach_TLBModException
  982. .set at
  983.  
  984.